import { cloneDeep } from 'lodash';
import {
  useCallback,
  useContext,
  useEffect,
  useLayoutEffect,
  useRef,
  useState,
} from 'react';
import TreeContext from './Context/TreeContext';
import MotionTreeNode from './MotionTreeNode';
import type { InternalFlattenNode, Key, NodeListProps } from './interface';
import { getTreeNodeProps } from './utils/treeUtils';

export const MOTION_KEY = `RC_TREE_MOTION_${Math.random()}`;

const motionFlatteNode: InternalFlattenNode = {
  key: MOTION_KEY,
  title: '',
  pos: '0',
  data: { key: MOTION_KEY },
  isStart: [],
  isEnd: [],
};

function NodeList(props: NodeListProps) {
  const {
    data,
    motion,
    expandedKeys,
    loadedKeys,
    loadingKeys,
    checkedKeys,
    halfCheckedKeys,
    selectedKeys,
  } = props;
  const { keyEntities } = useContext(TreeContext)!;
  const [prevExpendKeys, setPrevExpendKeys] = useState<Key[]>(expandedKeys);
  const [prevData, setPrevData] = useState<InternalFlattenNode[]>(data);
  const [transitionData, setTransitionData] = useState<InternalFlattenNode[]>(
    [],
  );
  const [transitonRange, setTransitionRange] = useState<InternalFlattenNode[]>(
    [],
  );
  const [motionType, setMotionType] = useState<'show' | 'hide'>();

  useEffect(() => {
    console.log('prevData', prevData)
    console.log('data', data);
  }, [data])

  // 通过鼠标手动触发的，expendKeys每次只会add/delte一个
  const _diffExpandedKeys = useCallback<
    (prev: Key[], next: Key[]) => { add: boolean; key: Key | null }
  >((prev, next) => {
    const prevLength = prev.length;
    const nextLength = next.length;
    if (Math.abs(prevLength - nextLength) !== 1) {
      return { add: false, key: null };
    }

    function findKey(shorter: Key[], longer: Key[]): Key | null {
      const shorterKeyMap = new Map<Key, boolean>();
      shorter.forEach((shorterKey) => {
        shorterKeyMap.set(shorterKey, true);
      });
      const keys = longer.filter((longerKey) => !shorterKeyMap.has(longerKey));
      return keys.length === 1 ? keys[0] : null;
    }

    //打开
    if (prevLength < nextLength) {
      return {
        add: true,
        key: findKey(prev, next),
      };
    }

    //关闭
    if (prevLength > nextLength) {
      return {
        add: false,
        key: findKey(next, prev),
      };
    }
    return { add: false, key: null };
  }, []);

  //要把删除/新增的内容摘出来
  const _getExpendNodeRange = useCallback<
    (
      shorter: InternalFlattenNode[],
      longer: InternalFlattenNode[],
      key: Key,
    ) => InternalFlattenNode[]
  >((shorter, longer, key) => {
    const shortStartIndex = shorter.findIndex(
      (shorterItem) => shorterItem.key === key,
    );
    const shortEndNode = shorter[shortStartIndex + 1];
    if (shortEndNode) {
      //从中间打开
      const longEndIndex = longer.findIndex(
        (longerItem) => longerItem.key === shortEndNode.key,
      );
      return longer.slice(shortStartIndex + 1, longEndIndex);
    }
    return longer.slice(shortStartIndex + 1);
  }, []);

  useLayoutEffect(() => {
    // console.log('--NodeList--prevExpendKeys--expandedKeys--:', prevExpendKeys, expandedKeys);
    const diffExpanded = _diffExpandedKeys(prevExpendKeys, expandedKeys);
    const { key, add } = diffExpanded;
    //根据expendKeys的变化,找出transitionRange
    if (key) {
      //---待定 Tree--  conductExpandParent 会引起 expendedKeys的变化---待会测试
      let rangeNodes, newTransitionData, keyIndex;
      let currShowType: 'show' | 'hide' = 'show';
      if (add) {
        //由关闭到打开
        rangeNodes = _getExpendNodeRange(prevData, data, key);
        keyIndex = prevData.findIndex((dataItem) => dataItem.key === key);
        newTransitionData = cloneDeep(prevData);
        newTransitionData.splice(keyIndex + 1, 0, motionFlatteNode);
        currShowType = 'show';
      } else {
        //由打开到关闭
        rangeNodes = _getExpendNodeRange(data, prevData, key);
        keyIndex = data.findIndex((dataItem) => dataItem.key === key);
        newTransitionData = cloneDeep(data);
        newTransitionData.splice(keyIndex + 1, 0, motionFlatteNode);
        currShowType = 'hide';
      }
      setTransitionRange(rangeNodes); //lodaData存在时，rangeNodes有可能 === [];
      setTransitionData(newTransitionData);
      setMotionType(currShowType);
      // console.log('--NodeList--useLayoutEffect--2.onExpand触发--打开--newTransitionData--rangeNodes--keyEntities--:', newTransitionData, rangeNodes, keyEntities)
      // setTimeout(() => {
      //   handleMotionEnd();
      // }, 3000)
    } else if (prevData !== data) {
      //treeData的变换引起flatteNodes的变化
      setPrevData(data);
      setTransitionData(data);
      setTransitionRange([]);
    }
    setPrevExpendKeys([...expandedKeys]);
  }, [data, expandedKeys]);

  const mergedData = motion ? transitionData : data;
  // console.log('--NodeList--mergedData--:', mergedData);

  const dataRef = useRef(data);
  dataRef.current = data;
  //动画执行完毕
  const handleMotionEnd = () => {
    const latestData = dataRef.current;
    // console.log('--NodeList--3.onExpand触发--onMotionEnd触发--动画完成，还原数据--:', latestData);

    setPrevData(latestData);
    setTransitionData(latestData);
    setTransitionRange([]);
    setMotionType(undefined);
  };

  return (
    <>
      {mergedData.map((treeNode) => {
        const { key, isStart, isEnd, title, data } = treeNode;
        const treeNodeRequiredProps = getTreeNodeProps(
          key,
          {
            expandedKeys,
            loadingKeys,
            loadedKeys,
            checkedKeys,
            halfCheckedKeys,
            selectedKeys,
          },
          keyEntities,
        );
        return (
          <MotionTreeNode
            key={key}
            eventKey={key}
            title={title}
            isStart={isStart}
            isEnd={isEnd}
            data={data}
            motion={motion}
            motionType={motionType!}
            motionNodes={key === MOTION_KEY ? transitonRange : null}
            onMotionEnd={handleMotionEnd}
            expandedKeys={expandedKeys}
            loadingKeys={loadingKeys}
            loadedKeys={loadedKeys}
            checkedKeys={checkedKeys}
            halfCheckedKeys={halfCheckedKeys}
            selectedKeys={selectedKeys}
            treeNodeRequiredProps={treeNodeRequiredProps}
          />
        );
      })}
    </>
  );
}

export default NodeList;
